<template>
  <transition
    :name="animation?'dialog-fade':''"
  >
    <div v-show="visible" class="c-model-wapper" :style="{zIndex:conStyle.zIndex}">
      <div v-if="mask" :style="{zIndex:conStyle.zIndex}" class="c-modal-mask" @click.self="handleClickMask"/> 
      <div
        ref="modal"
        class="c-modal"
        :style="conStyle"
        @click="handleModalClick"
      >

        <div v-if="showTitle" class="c-modal--title g-flex" style="height: 28px" @mousedown="handleTitleMouseDown">
          <div class="g-flex-1">
            <slot name="title"><span class="g-fs-14 " style="line-height: 28px">{{ title }}</span></slot>
          </div>
          <template v-if="showSizer">
            <div v-if="sizerState==='normal'" class="g-flex-0 _close-btn" @click.stop="handleSizeChange('small')">
              <img src="statics/icons/simulation/topicon1.png"  />
            </div>
            <div  v-else-if="sizerState==='small'" class="g-flex-0 _close-btn" @click.stop="handleSizeChange('normal')">
              <img src="statics/icons/simulation/topicon2.png"  />
            </div>
            <div  v-else-if="sizerState==='large'" class="g-flex-0 _close-btn" @click.stop="handleSizeChange('normal')">
              <img src="statics/icons/simulation/iconreturn.svg"  />
            </div>

          </template>
          <div v-if="showClose" class="g-flex-0 _close-btn" @click.stop="$emit('cancel')">
            <img src="statics/icons/simulation/topicon3.png"  />
          </div>

        </div>
        <div class="c-modal--content">
          <slot></slot>
 
        </div>
        <div v-if="showFooter" class="c-modal--footer">
          <slot name="footer">
            <a-button v-if="cancelText" class="cancel-btn g-m-r-12" @click="$emit('cancel')">{{cancelText}}</a-button>
            <a-button
              v-if="centerBtnText"
              class="g-m-r-10"
              :disabled="cancelDisabled"
              @click="$emit('click-center')">{{centerBtnText}}
            </a-button>
            <a-button
              v-if="okText"
              type="primary"
              :loading="okLoading"
              :disabled="confirmDisabled"
              @click.stop="$emit('ok')">{{okText}}
            </a-button>
          </slot>
        </div>
        <template v-if="resizable">
          <div class="c-modal--sizer _top" @mousedown="handleSizerMouseDown($event,'top')"/>
          <div class="c-modal--sizer _bottom" @mousedown="handleSizerMouseDown($event,'bottom')"/>
          <div class="c-modal--sizer _left" @mousedown="handleSizerMouseDown($event,'left')"/>
          <div class="c-modal--sizer _right" @mousedown="handleSizerMouseDown($event,'right')"/>
          <div class="c-modal--sizer _top-left" @mousedown="handleSizerMouseDown($event,'top-left')"/>
          <div class="c-modal--sizer _top-right" @mousedown="handleSizerMouseDown($event,'top-right')"/>
          <div class="c-modal--sizer _bottom-left" @mousedown="handleSizerMouseDown($event,'bottom-left')"/>
          <div class="c-modal--sizer _bottom-right" @mousedown="handleSizerMouseDown($event,'bottom-right')"/>
        </template>

      </div> 
    </div>
  </transition>

</template>
<script>
//// 模态框实例数组，用于计算z-index
const modalInstanceList = [];
//// 窗口拖动条高度，electron下才会有
//// const windowBarHeight = process.platform !== "browser" ? 32 : 0;

export default {
  name: "custom-modal",
  props: {
    showTitle: {
      type: Boolean,
      default: true,
    },
    title: {
      type: String,
      default: "Title",
    },
    value: Boolean,
    keepAlive: Boolean,
    okText: {
      type: String,
      default: "确定",
    },
    cancelDisabled: {
      type: Boolean,
      default: false,
    },
    confirmDisabled: {
      type: Boolean,
      default: false,
    },
    cancelText: {
      type: String,
      default: "取消",
    },
    centerBtnText: {
      type: String,
      default: "",
    },
    width: { 
      type: Number,
      default: 736,
    },
    height: Number,
    minWidth: { //// resizable==true时生效,如果没传则会以height作为最小高度
      type: Number,
    },
    minHeight: { //// resizable==true时生效，如果没传则会以width作为最小高度
      type: Number,
    },

    top: Number, //// 如果没传则默认会以document高度的15%的top位置 
    left: Number, //// 如果没传则默认会计算出一个使弹窗居中的left值
    center: Boolean, //// 开启居中模式
    showFooter: {
      type: Boolean,
      default: true,
    },
    showSizer: Boolean, //// 是否显示放大缩小按钮
    showClose: {
      type: Boolean,
      default: true,
    },
    mask: Boolean, //// 是否显示遮罩

    okLoading: Boolean,
    resizable: Boolean, //// 是否可缩放弹窗的宽高
    animation: Boolean,
    initSize: { //// 初始大小
      type: String,
      default: 'normal'
    },
    closeOnProjectSwitch: Boolean

  },
  data() {
    const docWidth =  document.body.offsetWidth;
    const docHeight = document.body.offsetHeight;
    const width = this.width + 'px';
    let height;
    if (this.height !== undefined){
      height = this.height + 'px';
    } else if (this.resizable){
      height = 500 + 'px';
    } else {
      height = 'auto';
    }

    let left;
    let top;
    if (this.left === undefined){
      left = (docWidth -  this.width) * 0.5 + 'px';
    } else {
      left = this.left + 'px';
    }
    if (this.top === undefined){
      top = docHeight * 0.15 + 'px';
    } else {
      top = this.top + 'px';
    }
    if (this.resizable){
      this._minWidth = this.minWidth || this.width;
      this._minHeight = this.minHeight || this.height;
      
    }
    const windowBarHeight = this.$globalConfig.isElectron ? 32 : 0;
    const data =  {
      visible: this.value,
      windowBarHeight,
      conStyle: {
        zIndex: this.getZIndex(),
        width,
        left,
        top,
        height,
        //// boxShadow: '' //// : 0px 9px 28px 8px rgb(0 0 0 / 5%), 0px 6px 16px 0px rgb(0 0 0 / 8%), 0px 3px 6px -4px rgb(0 0 0 / 12%);
      },
      sizerState: this.initSize, //// small / large / normal
      sizerMovaHandler: this.resizable && {
        top: (startBounds, startPoint, newPoint) => {
          if (newPoint.y < windowBarHeight) return;
          const top = startBounds.y + newPoint.y - startPoint.y;
          const height = startBounds.height - (newPoint.y - startPoint.y);
          if (height < this._minHeight) return;
          this.conStyle.top = top + 'px';
          this.conStyle.height = height + 'px';

        },
        bottom: (startBounds, startPoint, newPoint) => {
          if (newPoint.y > document.body.offsetHeight) return;
          const height = startBounds.height + newPoint.y - startPoint.y;
          if (height < this._minHeight) return;
          this.conStyle.height = height + 'px';
        },
        left: (startBounds, startPoint, newPoint) => {
          if (newPoint.x < 0) return;
          const left = startBounds.x + newPoint.x - startPoint.x;
          const width = startBounds.width - (newPoint.x - startPoint.x);
          if (width < this._minWidth) return;
          this.conStyle.left = left + 'px';
          this.conStyle.width = width + 'px';

        },
        right: (startBounds, startPoint, newPoint) => {
          if (newPoint.x > document.body.offsetWidth) return;
          const width = startBounds.width + newPoint.x - startPoint.x;
          if (width < this._minWidth) return;
          this.conStyle.width = width + 'px';
          
        },
        'top-left': (startBounds, startPoint, newPoint) => {
          this.sizerMovaHandler.top(startBounds, startPoint, newPoint);
          this.sizerMovaHandler.left(startBounds, startPoint, newPoint);

        },
        'top-right': (startBounds, startPoint, newPoint) => {
          this.sizerMovaHandler.top(startBounds, startPoint, newPoint);
          this.sizerMovaHandler.right(startBounds, startPoint, newPoint);
          
        },
        'bottom-left': (startBounds, startPoint, newPoint) => {
          this.sizerMovaHandler.bottom(startBounds, startPoint, newPoint);
          this.sizerMovaHandler.left(startBounds, startPoint, newPoint);
          
        },
        'bottom-right': (startBounds, startPoint, newPoint) => {
          this.sizerMovaHandler.bottom(startBounds, startPoint, newPoint);
          this.sizerMovaHandler.right(startBounds, startPoint, newPoint);
          
        },

      },
      events: { }
      
    };
    if (this.closeOnProjectSwitch){
      data.events['project-switch'] = () => this.$emit('cancel');
    }
    return data;
  },
  computed: {
    opacity() {
      return this.visible ? 1 : 0;
    },
  },
  watch: {
    value(val) {
      this.visible = val;
    },
    "$route.path"() {
      if (!this.keepAlive) {
        this.$emit("cancel");
      }
    },
    height(val){
      this.conStyle.height = val + 'px';
    }
  },
  created() {
    modalInstanceList.push(this);
  },
  mounted() {
    ////
    //// setTimeout(() => {
    ////   this.conStyle.zIndex = this.getZIndex();
    //// }, 100);
    if (this.center) {
      this.setModalCenter();
    }
    this.$bus.onBatch(this.events);
    //// app.$bus.on('project-switch', this.closeModal,);
  },
  beforeDestroy() {
    clearInterval(this.maskTimer);
    this.$bus.offBatch(this.events);
    //// this.maskTimer
    const index = modalInstanceList.findIndex(
      (instance) => instance === this
    );
    if (index > -1) {
      modalInstanceList.splice(index, 1);
    }
  },
  methods: {
    getZIndex() {
      const list = modalInstanceList.filter((i) => i !== this);
      if (list.length === 0) return 1000;
      const zIndexArr = list.map((i) => i.conStyle.zIndex);
      const maxZIndex = Math.max(...zIndexArr, 1000);
      return maxZIndex + 1;
    },
    getTop(top) {
      const modal = this.$refs.modal;
      top =
        top <= 0
          ? 0
          : top >= document.body.offsetHeight - modal.offsetHeight - 1
            ? document.body.offsetHeight - modal.offsetHeight - 1
            : top;
      if (top < this.windowBarHeight) {
        top = this.windowBarHeight;
      }
      return top;
    },
    getLeft() {},

    handleTitleMouseDown() {
      const modal = this.$refs.modal;
      let X = event.clientX - modal.offsetLeft;
      let Y = event.clientY - modal.offsetTop;
      const mouseMoveHandler = (event) => {
        let left = event.clientX - X;
        let top = event.clientY - Y;
        left =
          left <= 0
            ? 0
            : left >=
              document.body.offsetWidth - modal.offsetWidth - 1
              ? document.body.offsetWidth - modal.offsetWidth - 1
              : left;
        top = this.getTop(top);
        requestAnimationFrame(() => {
          this.conStyle.left = left + "px";
          this.conStyle.top = top + "px";
        });
      };
      const mouseUpHandler = (event) => {
        window.removeEventListener("mousemove", mouseMoveHandler);
        window.removeEventListener("mouseup", mouseUpHandler);
      };
      window.addEventListener("mousemove", mouseMoveHandler);
      window.addEventListener("mouseup", mouseUpHandler);
      this.$emit('title-mouse-down', window.event);
    },
    handleModalClick() {
      this.conStyle.zIndex = this.getZIndex();
    },
    handleSizeChange(size) {
      this.sizerState = size;
      this.$emit("size-change", size);
    },
    handleSizerMouseDown(event, type){
      const startPoint = { x: event.clientX, y: event.clientY };
      const startBounds = {
        x: parseInt( this.conStyle.left),
        y: parseInt(this.conStyle.top),
        width: parseInt(this.conStyle.width),
        height: parseInt(this.conStyle.height),
      };
      const handler = this.sizerMovaHandler[type];
      const mouseMoveHandler = (event2) => {
        const newPoint = { x: event2.clientX, y: event2.clientY };
        handler(startBounds, startPoint, newPoint);

      };
      const mouseUpHandler = () => {
        window.removeEventListener("mousemove", mouseMoveHandler);
        window.removeEventListener("mouseup", mouseUpHandler);

      };
      window.addEventListener("mousemove", mouseMoveHandler);
      window.addEventListener("mouseup", mouseUpHandler);

    },

    //// 窗口居中
    setModalCenter() {
      const modal = this.$refs.modal;
      this.$nextTick(() => {
        const height = modal.offsetHeight;
        const docHeight = document.body.offsetHeight;
        const top = (docHeight - height) / 2;
        this.$set(this.conStyle, 'top', top + 'px');
      });
    },
    getCurrentHeight(){
      return parseFloat(this.conStyle.height);
    },
    handleClickMask(){
      clearInterval(this.maskTimer);
      let num = 0;
      this.maskTimer = setInterval(() => {
        if (num % 2 === 0){
          this.$set(this.conStyle, 'boxShadow', 'none');

        } else {
          this.$delete(this.conStyle, 'boxShadow');
        }
        num++; ;
        if (num >= 6) {
          clearInterval(this.maskTimer);
        }
        
      }, 80);

    },
  },
};
</script>
<style lang="scss">
.dialog-fade-enter-active {
  animation: dialog-fade-in .3s;
}

.dialog-fade-leave-active {
  animation: dialog-fade-out .3s;
}

@keyframes dialog-fade-in {
  0% {
    transform: translate3d(0, -20px, 0);
    opacity: 0;
  }
  100% {
    transform: translate3d(0, 0, 0);
    opacity: 1;
  }
}

@keyframes dialog-fade-out {
  0% {
    transform: translate3d(0, 0, 0);
    opacity: 1;
  }
  100% {
    transform: translate3d(0, -20px, 0);
    opacity: 0;
  }
}
.c-model-wapper {
  //// transition: opacity 0.2s ease;
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
}
.c-modal-mask {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(100, 100, 100, 0);
}
.c-modal {
  position: fixed;
  box-sizing: border-box;
  width: 736px;
  box-shadow: 0px 9px 28px 8px rgba(0, 0, 0, 0.05),
    0px 6px 16px 0px rgba(0, 0, 0, 0.08),
    0px 3px 6px -4px rgba(0, 0, 0, 0.12);
  border-radius: 0px;
  background: #ffffff;
  display: flex;
  flex-direction: column;
  border: 1px solid #B1CEE2;
  .c-modal--title {
    overflow: hidden;
    color: #ffffff;
    background: linear-gradient(90deg, #4390c1 0%, #236fa0 100%);
    padding-left: 20px;
    height: 32px;
    ._close-btn {
      width: 30px;
      text-align: center;
      line-height: 25px;
      cursor: pointer;
      &:hover {
        background: rgba(157, 17, 18, 1);
      }
    }
     flex: 0 0 auto;
  }
  .c-modal--content {
    margin: 0;
    font-size: 12px;
    flex: 1;
    overflow: hidden;
  }
  .c-modal--footer {
    overflow: hidden;
    //// height: 40px;
    border-top: 1px solid #eee;
    text-align: right;
    padding: 12px 20px;
    flex: 0 0 auto;
    button {
      border-radius: 0;
    }
  }
  .c-modal--sizer {
    background: rgba(0, 0, 0, 0);
    position: absolute;
    &._top {
      width: 100%;
      height: 4px;
      top: 0;
      left: 0;
      cursor: ns-resize;
    }
    &._bottom {
      width: 100%;
      height: 4px;
      bottom: 0;
      left: 0;
      cursor: ns-resize;
    }
    &._left {
      height: 100%;
      width: 4px;
      top: 0;
      left: 0;
      cursor: ew-resize;
    }
    &._right {
      height: 100%;
      width: 4px;
      top: 0;
      right: 0;
      cursor: ew-resize;
    }
    &._top-left {
      width: 4px;
      height: 4px;
      top: 0;
      left: 0;
      cursor: nwse-resize;
    }
    &._top-right {
      width: 4px;
      height: 4px;
      top: 0;
      right: 0;
      cursor: nesw-resize;
    }
    &._bottom-left {
      width: 4px;
      height: 4px;
      bottom: 0;
      left: 0;
      cursor: nesw-resize;
    }
    &._bottom-right {
      width: 4px;
      height: 4px;
      bottom: 0;
      right: 0;
      cursor: nwse-resize;
    }
  }
}
</style>
